(library (math)
  (export PI
          sine*
          make-sine-func
          float->scaled-truncated-integer)
  (import (except (rnrs base) let-values vector-for-each)
          (only (guile)
                lambda* λ
                inexact->exact
                truncate))

  (define PI (* 4 (atan 1.0)))

  (define modify-argument
    (λ (func modifier)
      (λ (x)
        (func
         (modifier x)))))

  (define offset
    (λ (func shift)
      (modify-argument func
                       (λ (x) (+ x shift)))))

  (define modify-result
    (λ (func modifier)
      (λ (x)
        (modifier (func x)))))

  (define amplify-*
    (λ (func amplification)
      (modify-result func
                     (λ (x) (* x amplification)))))

  (define amplify-+
    (λ (func amplification)
      (modify-result func
                     (λ (x) (+ x amplification)))))

  (define sine*alt
    (lambda* (x #:key (amplitude 1) (frequency 1) (phase-offset 0))
      ((amplify-*
        (offset (modify-argument sin (λ (arg) (* 2 PI frequency arg)))
                phase-offset)
        amplitude)
       x)))

  ;; idea:
  ;; modify result? -- amplify
  ;; modify argument? -- change freq., phase offset


  (define sine*
    (lambda* (x #:key (amplitude 1) (frequency 1) (phase-offset 0))
      "Calculate the value of a modified sine function. The sine
function is modified by amplitude, frequency and phase
offset. The defaults make a sine function, which rotates a
full circle in 1 second."
      ;; Multiplying by the amplitude make the resulting
      ;; value of the sine function smaller or bigger, in
      ;; effect changing the amplitude.
      (* amplitude
         ;; Use the standard sine function, but modify its
         ;; argument.
         (sin
          ;; Adding to the argument of the sine function
          ;; will give the result of a bigger or smaller
          ;; input value, in effect shifting the along the
          ;; x-axis.
          (+ (*
              ;; Multiplying by 2*pi changes the sine function
              ;; so that it goes full circle in [0;1]. This is
              ;; so, because usually the since function would
              ;; only do 1/2pi of circle within [0;1].
              2 PI
              ;; Multiplying with the frequency makes it so,
              ;; that frequency full circles are in [0;1].
              frequency
              ;; x is the actual argument for the modified
              ;; sine function.
              x)
             phase-offset)))))

  (define make-sine-func
    (lambda* (#:key (amplitude 1) (frequency 1) (phase-offset 0))
      "Make a sine function, given the amplitude, frequency and
phase offset."
      (λ (x)
        (sine* x
               #:amplitude amplitude
               #:frequency frequency
               #:phase-offset phase-offset))))

  (define float->scaled-truncated-integer
    (λ (num scale)
      (inexact->exact
       (truncate
        (* num scale))))))
